<template>
  <div v-loading="state.loading">
    <QueryFrom v-if="$slots.queryItem" class="query-form" :query-form-data="props.queryFormData" @query="query">
      <template #queryItem>
        <slot name="queryItem"></slot>
      </template>
      <template v-if="$slots.moreQuery" #moreQuery>
        <slot name="moreQuery"></slot>
      </template>
    </QueryFrom>

    <el-row v-if="props.showTableTop" class="top-btn flex-row-center-left mgt5 mgb15">
      <el-button v-if="props.showTopAddBtn" type="primary" @click="handleUpdateOrAdd(props.addData, 'add')">新增</el-button>
      <el-button v-if="props.showDelBtn" type="danger" :disabled="!state.selectedList.length" @click="handleDeleteRowById(null)">删除</el-button>
      <slot name="topExtra" v-bind="state"></slot>
    </el-row>

    <div style="position: relative">
      <el-table :data="props.dataListApi ? state.dataList : props.dataList" border :max-height="state.tableHeigt" @selection-change="onSelectionChange" v-bind="$attrs">
        <el-table-column v-for="item in props.columnConfig" :key="item.prop" header-align="center" align="center" v-bind="item">
          <template v-if="item.slot" #default="slotProps">
            <slot :name="item.slot" v-bind="slotProps"></slot>
          </template>
        </el-table-column>

        <el-table-column v-if="props.showActionColumn" label="操作" fixed="right" :width="props.actionColumnWidth" header-align="center" align="center">
          <template #default="{ row }">
            <slot name="extraBtn1" :row="row"></slot>
            <el-button v-if="$slots.dialogUpdateOrAdd" type="primary" link @click="handleUpdateOrAdd(row, 'update')">修改</el-button>
            <slot name="extraBtn2" :row="row"></slot>
            <el-button v-if="props.showDelBtn" type="danger" link @click="handleDeleteRowById(row)">删除</el-button>
            <slot name="extraBtn3" :row="row"></slot>
          </template>
        </el-table-column>

        <template #empty>
          <div class="flex-column-center-center">
            <SvgIcon :width="100" :height="100" name="empty-data" color="#606266" />
            <span>暂无数据~</span>
          </div>
        </template>
      </el-table>

      <el-pagination
        v-show="props.dataListApi && !state.loading"
        class="pagination"
        v-model:current-page="queryParams.currentPage"
        v-model:page-size="queryParams.pageSize"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="state.total"
        @size-change="query"
        @current-change="query"
      />
    </div>

    <DialogVue
      v-if="state.isShowDialog"
      ref="dialogEl"
      :width="props.dialogWidth"
      :title="state.dialogType === 'add' ? `新增${props.moduleName}` : `修改${props.moduleName}`"
      :api-method="state.dialogType === 'add' ? 'post' : 'put'"
      :form-data="state.dialogUpdateOrAddData"
      :api="props.updateOrAddApi"
      :rules="props.dialogFormRules"
      @closed="state.isShowDialog = false"
      @before-submit="onBeforeSubmit"
      @submit-success="query"
      @refactor-params="emits('refactor-dialog-params', state.dialogType, $event)"
    >
      <slot name="dialogUpdateOrAdd" :row="state.dialogUpdateOrAddData"></slot>
    </DialogVue>
  </div>
</template>

<script setup lang="ts">
  import { ref, toRefs, reactive, onMounted, onUnmounted, nextTick } from 'vue'
  import QueryFrom from '@/components/query-form'
  import DialogVue, { type DialogVueInstance, type ValidateFn } from '@/components/dialog'
  import type { IColumnConfig } from '../index'
  import { Ui } from '@/utils'
  import request from '@/service'
  import { clone } from 'xe-utils'

  interface IEmits {
    (e: 'before-open-dialog', type: IDialogType, data: any): void
    (e: 'before-submit', data: any, fn: ValidateFn): void
    (e: 'refactor-data', data: any[]): void
    (e: 'refactor-dialog-params', type: IDialogType, data: any): void
    (e: 'refactor-query-params', data: any): void
  }

  const emits = defineEmits<IEmits>()

  const onBeforeSubmit = (data: any, fn: ValidateFn) => {
    emits('before-submit', data, fn)
  }

  const props = defineProps({
    queryFormData: {
      type: Object,
      default: () => ({})
    },
    columnConfig: {
      type: Array<IColumnConfig>,
      default: () => []
    },
    dataListApi: {
      type: String,
      default: ''
    },
    dataList: {
      type: Array,
      default: () => []
    },
    deleteApi: {
      type: String,
      default: ''
    },
    useParamsDelete: {
      type: Boolean,
      default: false
    },
    updateOrAddApi: {
      ype: String,
      default: ''
    },
    pageSize: {
      type: Number,
      default: 100
    },
    addData: {
      type: Object,
      default: () => ({})
    },
    moduleName: {
      type: String,
      default: ''
    },
    dialogFormRules: {
      type: Object,
      default: () => ({})
    },
    actionColumnWidth: {
      type: Number,
      default: 180
    },
    showTableTop: {
      type: Boolean,
      default: true
    },
    showActionColumn: {
      type: Boolean,
      default: true
    },
    showDelBtn: {
      type: Boolean,
      default: true
    },
    showTopAddBtn: {
      type: Boolean,
      default: true
    },
    dialogWidth: {
      type: Number,
      default: 800
    },
    onMountedQuery: {
      type: Boolean,
      default: true
    }
  })

  const dialogEl = ref<DialogVueInstance | null>()

  const queryParams = reactive({
    currentPage: 1,
    pageSize: props.pageSize
  })

  type IDialogType = 'add' | 'update'

  const state = reactive({
    loading: false,
    total: 0,

    tableHeigt: 500,
    dataList: [] as any[], // 表格数据
    selectedList: [] as any[],
    dialogUpdateOrAddData: {} as any,
    dialogType: '' as IDialogType,
    isShowDialog: false
  })

  /**----------------------------methods----------------------------------------------------------------------- */

  /**
   *
   * @param list 选中行
   */
  const onSelectionChange = (list: any[]) => {
    state.selectedList = list
  }

  /**
   * 列表新增或修改
   * @param data
   * @param type
   */
  const handleUpdateOrAdd = async (data: any, type: IDialogType) => {
    state.dialogUpdateOrAddData = type === 'add' ? data : clone(data, true)
    state.dialogType = type
    emits('before-open-dialog', type, state.dialogUpdateOrAddData)
    state.isShowDialog = true

    await nextTick()

    dialogEl.value?.handleOpen()
  }

  /**
   * 删除数据
   * @param row
   */
  const handleDeleteRowById = (row: any) => {
    const handleConfirm = () => {
      const { deleteApi, useParamsDelete } = props
      // id 拼接在路径后面
      const api = useParamsDelete ? `${deleteApi}/${row.id}` : deleteApi
      const idList = row ? [row.id] : state.selectedList.map(item => item.id)

      request.delete(api, useParamsDelete ? null : idList).then(res => {
        if (res.code !== 0) return Ui.useMessage('error', res.msg)

        Ui.useMessage('success', res.msg)
        query()
      })
    }

    Ui.useMessageBox({
      handleConfirm
    })
  }

  /**
   * 查询数据
   */
  const query = () => {
    if (!props.dataListApi) return
    state.loading = true
    const params = {
      current: queryParams.currentPage,
      size: queryParams.pageSize,
      ...props.queryFormData
    }

    emits('refactor-query-params', params)

    request
      .get(props.dataListApi, params)
      .then(res => {
        if (res.code !== 0) return Ui.useMessage('error', res.msg)
        if (res.data?.records && res.data.records?.length) {
          emits('refactor-data', res.data.records)
          state.dataList = res.data.records
          state.total = res.data.total
        } else if (res.data && res.data.length) {
          emits('refactor-data', res.data)
          state.dataList = res.data
        } else {
          state.total = 0
          state.dataList = []
        }
      })
      .finally(() => (state.loading = false))
  }

  const calTableHeight = () => {
    const queryFormEl = document.querySelector('.query-form')
    const topBtnEl = document.querySelector('.top-btn')
    state.tableHeigt = window.innerHeight - (queryFormEl?.clientHeight ?? 0) - (topBtnEl?.clientHeight ?? 0) - 220
  }

  const setupInit = () => {
    if (props.onMountedQuery) {
      query()
    }
  }

  /**----------------------------lifecycle----------------------------------------------------------------------- */

  setupInit()

  onMounted(() => {
    window.addEventListener('resize', calTableHeight)

    calTableHeight()
  })

  onUnmounted(() => {
    window.removeEventListener('resize', calTableHeight)
  })

  defineExpose({
    query,
    handleUpdateOrAdd,
    ...toRefs(state),
    ...toRefs(queryParams)
  })
</script>

<style scoped>
  .pagination {
    position: absolute;
    bottom: -45px;
    right: 20px;
  }
</style>
